package demo5

import (
	"context"
	"fmt"
	"sync"
	"time"
)

var wg sync.WaitGroup

func worker() {
	for {
		time.Sleep(time.Second)
		fmt.Println("哈哈")
	}
	// 如何优雅的释放
	wg.Done()
}

func test01() {
	// 第一种方法
	wg.Add(1)
	// 如何优雅的退出
	go worker()
	wg.Wait()
	fmt.Println("over...")
}

// --------------------------------------------------------
var exit bool

func worker2() {
	for {
		time.Sleep(time.Second)
		fmt.Println("哈哈")
		if exit {
			break // 通过全局变量来退出
		}
	}
	// 如何优雅的释放
	wg.Done()
}
func test02() {
	// 第二种方法
	wg.Add(1)
	go worker2()
	time.Sleep(time.Second * 3)
	exit = true
	wg.Wait()
}

// --------------------------------------------------------
func worker3(ch <-chan bool) {
	for {
		time.Sleep(time.Second)
		fmt.Println("哈哈")
		if <-ch {
			break // 或者管道处理，但是这样比较危险，
		}
	}
	// 如何优雅的释放
	wg.Done()
}
func test03() {
	var ch chan bool
	ch = make(chan bool)
	wg.Add(1)
	go worker3(ch)
	ch <- true
	wg.Wait()
}

// --------------------------------------------------------
// context 版本 优雅而避免内存泄漏
func worker5(ctx context.Context) {
LOOP: // 再嵌套一层处理
	for {
		fmt.Println("循环5....")
		time.Sleep(time.Second)
		select {
		case <-ctx.Done(): // 优雅的退出
			{
				break LOOP
			}
		default:
		}
	}
}

func worker4(ctx context.Context) {
	go worker5(ctx) // 一层层的通知结束。。。。
LOOP:
	for {
		fmt.Println("循环....")
		time.Sleep(time.Second)
		select {
		case <-ctx.Done(): // 优雅的退出
			{
				break LOOP
			}
		default:
		}
	}
	wg.Done()
}

func test04() {
	// 方便管理子线程的生命周期
	ctx, cancel := context.WithCancel(context.Background())
	wg.Add(1)
	go worker4(ctx)
	time.Sleep(time.Second * 3) // 等待三秒
	cancel()                    // 通知groutine 结束 类似管道通知
	wg.Wait()
	fmt.Println("over ..")
}

// --------------------------------------------------------
// 超时取消，通常用到数据库连接等服务

func worker6(ctx context.Context) {
LOOP:
	for {
		fmt.Println("连接中.....")
		time.Sleep(time.Millisecond * 10) // 模拟连接消耗时间
		select {
		case <-ctx.Done():
			break LOOP
		}
	}
	fmt.Println("worker done...") // 方法运行完的结果
	wg.Done()
}

func test06() {
	// 50 毫秒自动调用ctx.Done
	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
	wg.Add(1)
	go worker6(ctx)
	// time.Sleep(time.Second * 5)
	cancel()
	wg.Wait()
	fmt.Println("over。。。。")
}

// --------------------------------------------------------
// 上下文传值
type MyContextInfo string

func worker7(ctx context.Context) {
	// 获取上下文的值
	key := MyContextInfo("TRACE_CODE")
	info, ok := ctx.Value(key).(string)
	if !ok {
		fmt.Println(ok)
	}
	fmt.Println("info:", info)
LOOP:

	for {
		fmt.Println("connection....")
		time.Sleep(time.Millisecond * 10)
		select {
		case <-ctx.Done():
			break LOOP
		}
	}
	fmt.Println("done...")
	wg.Done()
}

func test07() {
	// 搭配使用 加上超时时间....
	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
	// 传参上下文来使用，都是副本
	ctx = context.WithValue(ctx, MyContextInfo("TRACE_CODE"), "121212")
	wg.Add(1)
	go worker7(ctx)
	cancel()
	wg.Wait()
	fmt.Println("over")

}

func test08() {
	m := make(map[string]string, 1)
	fmt.Println(m["a"])
	fmt.Printf("%#v, %v", m["1"], m["1"])
}

func ContxtTest() {
	// test02()
	// test03()
	// test04()
	// test06()
	// test07()
	test08()
}
